package EnrynHsu.affiliate;


/**
 * JVM平台计算引擎
 */
public class NativeEngine implements ComputeEngine{


    @SuppressWarnings("all")
    public String operate(String n_1, String n_2, char op) {
        if (n_2.matches("^\\d+\\.$")) throw new ExpressParseException("小数写错了");
        Number n1 = null, n2 = null;
        try {
            n1 = Long.parseLong(n_1);
        } catch (NumberFormatException e1) {
            try {
                n1 = Double.parseDouble(n_1);
            } catch (NumberFormatException e) {
                throw new ExpressParseException("输入的数据中加入了不能解析的信息");
            }
        }
        try {
            n2 = Long.parseLong(n_2);
        } catch (NumberFormatException e1) {
            try {
                n2 = Double.parseDouble(n_2);
            } catch (NumberFormatException e) {
                throw new ExpressParseException("输入的数据中加入了不能解析的信息");
            }
        }

        return impl(n1,n2,op).toString();
    }

    /**
     * 运算
     * @param n1 左边的操作数
     * @param n2 右边的操作数
     * @param op 操作符
     * @return 结果，要么是Integer类型，要么是Double类型
     */
    static Number impl(Number n1, Number n2, char op) {

        int num1 = 0;
        int num2 = 0;

        // 如果是Integer，则标志设为0，否则为Double，则标志设为1
        if (n1 instanceof Long) ;
        else num1 = 1;
        if (n2 instanceof Long) ;
        else num2 = 1;

        // 如果要加入新的运算符，那么就按照同样的模式加入: 四种情况讨论，分别写一个return语句，返回运算结果
        switch (op) {
            case '+':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long)n1 + (Long)n2;
                            case 1: return (Long)n1 + (Double)n2;
                        }
                    case 1:
                        switch (num2) {
                            case 0: return (Double)n1 + (Long)n2;
                            case 1: return (Double)n1 + (Double)n2;
                        }
                }
            case '-':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long)n1 - (Long)n2;
                            case 1: return (Long)n1 - (Double)n2;
                        }
                    case 1:
                        switch (num2) {
                            case 0: return (Double)n1 - (Long)n2;
                            case 1: return (Double)n1 - (Double)n2;
                        }
                }
            case '*':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long)n1 * (Long)n2;
                            case 1: return (Long)n1 * (Double)n2;
                        }
                    case 1:
                        switch (num2) {
                            case 0: return (Double)n1 * (Long)n2;
                            case 1: return (Double)n1 * (Double)n2;
                        }
                }
            case '/':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: {
                                double res = (double) (Long) n1 / (double) (Long) n2;
                                long res_ = (Long) n1 / (Long) n2;
                                if (res_ != res) return res;
                                else return res_;
                            }
                            case 1: return (Long)n1 / (Double)n2;
                        }
                    case 1:
                        switch (num2) {
                            case 0: return (Double)n1 / (Long)n2;
                            case 1: return (Double)n1 / (Double)n2;
                        }
                }
            case '^':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return Math.pow((double)(Long)n1,(double)(Long) n2);
                            case 1: return Math.pow((Long)n1,(Double)n2);
                        }
                    case 1:
                        switch (num2) {
                            case 0: return Math.pow((Double)n1,(Long)n2);
                            case 1: return Math.pow((Double)n1,(Double)n2);
                        }
                }
            case '@':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return Math.log((double)(Long)n1) / Math.log((double)(Long) n2);
                            case 1: return Math.log((double)(Long)n1) / Math.log((Double)n2);
                        }
                    case 1:
                        switch (num2) {
                            case 0: return Math.log((Double)n1) / Math.log((Long)n2);
                            case 1: return Math.log((Double)n1) / Math.log((Double)n2);
                        }
                }
            case '%':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long) n1 % (Long) n2;
                            case 1:
                        }
                    case 1:
                        switch (num2) {
                            case 0:
                            case 1:
                        }
                    default: throw new ComputeException("取余的操作数必须是整数");
                }
            case '#':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long) n1 / (Long) n2;
                            case 1:
                        }
                    case 1:
                        switch (num2) {
                            case 0:
                            case 1:
                        }
                    default: throw new ComputeException("取商的操作数必须是整数");
                }
            case '&':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long) n1 & (Long) n2;
                            case 1:
                        }
                    case 1:
                        switch (num2) {
                            case 0:
                            case 1:
                        }
                    default: throw new ComputeException("按位与的操作数必须是整数");
                }
            case '|':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long) n1 | (Long) n2;
                            case 1:
                        }
                    case 1:
                        switch (num2) {
                            case 0:
                            case 1:
                        }
                    default: throw new ComputeException("按位或的操作数必须是整数");
                }
            case '~':
                switch (num1){
                    case 0:
                        switch (num2) {
                            case 0: return (Long) n1 ^ (Long) n2;
                            case 1:
                        }
                    case 1:
                        switch (num2) {
                            case 0:
                            case 1:
                        }
                    default: throw new ComputeException("按位异或的操作数必须是整数");
                }
                // TODO: 2/18/2023 模仿模式加入
        }

        // 如果运算符无法解析，那么抛出表达式无法解析异常
        throw new ComputeException("无法解析运算符" + op);
    }

}

